package com.visionblue.business.ship.page.collection

import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.visionblue.business.ship.BuildConfig
import com.visionblue.business.ship.base.ViewState
import com.visionblue.business.ship.ext.SingleLiveEvent
import com.visionblue.business.ship.modbus.DeviceControllerManager
import com.visionblue.business.ship.modbus.exception.ModbusError
import com.visionblue.business.ship.model.Results
import com.visionblue.business.ship.model.bean.local.*
import com.visionblue.business.ship.model.bean.request.PostApplicationRequest
import com.visionblue.business.ship.model.bean.response.ApplicationDetail
import com.visionblue.business.ship.model.bean.response.ShipInfo
import com.visionblue.business.ship.model.enums.ApplicationRecordStatusEnum
import com.visionblue.business.ship.model.enums.ApplicationTypeEnum
import com.visionblue.business.ship.model.enums.WasteTypeEnum
import com.visionblue.business.ship.model.repository.DeviceInfoRepository
import com.visionblue.business.ship.model.repository.FlowVolumeRepository
import com.visionblue.business.ship.model.repository.db.CachedOrder
import com.visionblue.business.ship.model.repository.db.CollectionRecord
import com.visionblue.business.ship.model.repository.db.MeasureMenuItem
import com.visionblue.business.ship.page.MainRepository
import com.visionblue.business.ship.page.applications.AbsApplicationsViewModel
import com.visionblue.business.ship.page.applications.ApplicationsRepository
import com.visionblue.business.ship.page.register.config.*
import com.visionblue.business.ship.util.FormatUtils
import com.visionblue.business.ship.util.MLog
import com.visionblue.business.ship.util.tickerFlow
import com.visionblue.business.ship.util.toast
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect

/**
 * @author: xlh
 * @date: 2020-05-19 2:26 PM
 * @desc:
 */
class CollectionViewModel(
    private val collectionRepository: CollectionRepository,
    private val deviceInfoRepository: DeviceInfoRepository,
    private val menuConfigRepository: MenuConfigRepository,
    private val flowVolumeRepository: FlowVolumeRepository,
    private val mainRepository: MainRepository,
    applicationsRepository: ApplicationsRepository
) :
    AbsApplicationsViewModel(applicationsRepository) {

//    private var volumeCounter: AtomicInteger = AtomicInteger(0)

    private var oilJob: Job? = null
    private var waterJob: Job? = null
    private var wasteWaterJob: Job? = null //新增废水
    private var weightJob: Job? = null
    private var sonicJob: Job? = null

//    private var flowChangeJob: Job? = null

    private var initOilFlowInfo: OilFlowInfo? = null
    private var initWaterFlowInfo: WaterFlowInfo? = null
    private var initWasteWaterFlowInfo: WaterFlowInfo? = null

    private var initSonicFlowInfo: UltraSonicFlowInfo? = null
    private var weightInfo: WeightInfo? = null
    private val cachedOrder = CachedOrder()
    private var lastWeightClickTime: Long = -1L
//    private var lastOilFlowInfo: OilFlowInfo? = null
//    private var lastWaterFlowInfo: WaterFlowInfo? = null

    val weightLiveData = MutableLiveData<Int>()

    val inCheckMode = MutableLiveData<Boolean>()

    val workStateLiveData = MutableLiveData<WorkStatus>()

    // 工作状态
//    val currWorkStatusLiveData = MutableLiveData(WorkStatus.BEFORE_WORK)

    // 工作类型
//    val currWorkTypeLiveData = MutableLiveData(WorkType.FLOW)

//    val flowType = MutableLiveData<FlowType>()

    val oilFlowInfoLiveData = MutableLiveData<OilFlowInfo>()
    val waterFlowInfoLiveData = MutableLiveData<WaterFlowInfo>()

    val wasteWaterFlowInfoLiveData = MutableLiveData<WaterFlowInfo>()

    val sonicInfoLiveData = MutableLiveData<UltraSonicFlowInfo>()

    val volumeErrorsLiveData = MutableLiveData<Set<VolumeErrorInfo>>()

//    val isShowProgressWeightGuide = SingleLiveEvent<Boolean>()

    val submitEvent = SingleLiveEvent<ViewState<PrintInfo>>()

    val menuItemsLiveData = MutableLiveData<List<MeasureMenuItem>>()

//    val flowNoChangeInWorkEvent = SingleLiveEvent<Boolean>()

    init {
        collectionRepository.recordsLiveData.value = mutableListOf()
    }

    override fun getApplicationStatus(): List<Int> {
        return listOf(ApplicationRecordStatusEnum.PROCESSING.status)
    }

    fun loadMenuItems(isOutput: Boolean) {
        viewModelScope.launch {
//            val menuItems = menuConfigRepository.getMenuItems()
//            menuItems.takeIf { it.isEmpty() }?.run {
//                menuConfigRepository.insert(
//                    arrayOf(
//                        MeasureMenuItem(WATER_VOLUME_NAME, "生活污水管"),
//                        MeasureMenuItem(OIL_VOLUME_NAME, "含油污水管"),
//                        MeasureMenuItem(WEIGHT_NAME, null),
//                        MeasureMenuItem(WATER_VOLUME_NAME, "生活污水管", isOutput = true),
//                        MeasureMenuItem(OIL_VOLUME_NAME, "含油污水管", isOutput = true),
//                        MeasureMenuItem(WEIGHT_NAME, null, isOutput = true)
//                    )
//                )
//            }
            menuItemsLiveData.value = menuConfigRepository.getMenuItemsByOutput(isOutput)
        }
    }

//    suspend fun loadMenuItemsSync(isOutput: Boolean): List<MeasureMenuItem> {
//        return menuConfigRepository.getMenuItemsByOutput(isOutput)
//    }

    // 读取输油管流量信息
    fun startWatchOilPipeInfo(
        measureMenuItem: MeasureMenuItem,
        isOutput: Boolean?,
        wasteTypeEnum: WasteTypeEnum
    ) {
        oilJob?.cancel()
        createLocalOilRecord(wasteTypeEnum, measureMenuItem)
        val iFlowVolumeErrorParser =
//            FakeInVolumeErrorParserImpl()
            if (isOutput == false) InFlowVolumeErrorParserImpl(flowVolumeRepository) else OutFlowVolumeErrorParserImpl(
                flowVolumeRepository
            )
        oilJob = viewModelScope.launch(Dispatchers.IO) {
//            lastOilFlowInfo = initOilFlowInfo
//            startCheckFlowChange()
            tickerFlow(1000).collect {
                try {
                    val oilFlowInfo = coroutineScope {
                        getOilFlowInfo(isOutput)
                    }

//                    if (lastOilFlowInfo?.positiveAccumulationVal != oilFlowInfo.positiveAccumulationVal) {
//                        restartCheckFlowChange()
//                    }

//                    lastOilFlowInfo = oilFlowInfo

                    // 计算重量
                    if (initOilFlowInfo == null) {
                        initOilFlowInfo = oilFlowInfo
                        checkOilPipeError(
                            oilFlowInfo.positiveAccumulationVal, iFlowVolumeErrorParser
                        )
                    } else {
                        collectionRepository.updateOilWeight(initOilFlowInfo, oilFlowInfo)
                    }

                    // 更新本地油管流量计计数
                    if (oilFlowInfo.positiveAccumulationVal > 0.0) {
                        iFlowVolumeErrorParser.updateOilVolume(oilFlowInfo.positiveAccumulationVal.toString())
                    }

                    withContext(Dispatchers.Main) {
                        oilFlowInfoLiveData.value = oilFlowInfo
                    }
                    MLog.e(oilFlowInfo.toString())
                } catch (e: ModbusError) {
                    MLog.e("oil modBus error: %s", e.message)
                }
            }
        }
        workStateLiveData.value = WorkStatus.WORKING
    }

//    private fun CoroutineScope.startCheckFlowChange() {
//        flowChangeJob = launch {
//            delay(5000)
//            flowNoChangeInWorkEvent.postValue(true)
//        }
//    }
//
//    private fun CoroutineScope.restartCheckFlowChange() {
//        flowChangeJob?.cancel()
//        flowNoChangeInWorkEvent.postValue(false)
//        startCheckFlowChange()
//    }


    fun startWatchWaterPipeInfo(
        measureMenuItem: MeasureMenuItem,
        isOutput: Boolean?,
        wasteTypeEnum: WasteTypeEnum
    ) {
        waterJob?.cancel()
        createLocalWaterRecord(measureMenuItem, wasteTypeEnum)
        val iFlowVolumeErrorParser =
//            FakeInVolumeErrorParserImpl()
            if (isOutput == false) InFlowVolumeErrorParserImpl(flowVolumeRepository) else OutFlowVolumeErrorParserImpl(
                flowVolumeRepository
            )
        waterJob = viewModelScope.launch(Dispatchers.IO) {
//            startCheckFlowChange()
//            lastWaterFlowInfo = initWaterFlowInfo
            tickerFlow(1000).collect {
                try {
                    val waterFlowInfo = coroutineScope {
                        getWaterFlowInfo(isOutput)
                    }

//                    if (initWaterFlowInfo?.positiveAccumulationVal != waterFlowInfo.positiveAccumulationVal) {
//                        restartCheckFlowChange()
//                    }

//                    lastWaterFlowInfo = waterFlowInfo

                    if (initWaterFlowInfo == null) {
                        Log.e("--->","1")
                        initWaterFlowInfo = waterFlowInfo
                        checkWaterPipeError(
                            waterFlowInfo.positiveAccumulationVal,
                            iFlowVolumeErrorParser
                        )
                    } else {
                        Log.e("--->","2")
                        collectionRepository.updateWaterWeight(initWaterFlowInfo, waterFlowInfo)
                    }

                    // 更新水地油管流量计计数
                    if (waterFlowInfo.positiveAccumulationVal > 0.0) {
                        iFlowVolumeErrorParser.updateWaterVolume(waterFlowInfo.positiveAccumulationVal.toString())
                    }

                    withContext(Dispatchers.Main) {
                        waterFlowInfoLiveData.value = waterFlowInfo
                    }

                    MLog.e(waterFlowInfo.toString())
                } catch (e: ModbusError) {
                    MLog.e("water modBus error: %s", e.message)
                }
            }
        }
        workStateLiveData.value = WorkStatus.WORKING
    }

    //新增-含油污水-start
    fun startWatchWasteWaterPipeInfo(
        measureMenuItem: MeasureMenuItem,
        isOutput: Boolean?,
        wasteTypeEnum: WasteTypeEnum
    ) {
        wasteWaterJob?.cancel()
        createLocalWasteWaterRecord(measureMenuItem, wasteTypeEnum)
        val iFlowVolumeErrorParser =
//            FakeInVolumeErrorParserImpl()
            if (isOutput == false) InFlowVolumeErrorParserImpl(flowVolumeRepository) else OutFlowVolumeErrorParserImpl(
                flowVolumeRepository
            )
        wasteWaterJob = viewModelScope.launch(Dispatchers.IO) {
//            startCheckFlowChange()
//            lastWaterFlowInfo = initWaterFlowInfo
            tickerFlow(1000).collect {
                try {
                    val wasteWaterFlowInfo = coroutineScope {
                        getWasteWaterFlowInfo(isOutput)
                    }

//                    if (initWaterFlowInfo?.positiveAccumulationVal != waterFlowInfo.positiveAccumulationVal) {
//                        restartCheckFlowChange()
//                    }

//                    lastWaterFlowInfo = waterFlowInfo

                    if (initWasteWaterFlowInfo == null) {
                        initWasteWaterFlowInfo = wasteWaterFlowInfo
                        checkWasteWaterPipeError(
                            wasteWaterFlowInfo.positiveAccumulationVal,
                            iFlowVolumeErrorParser
                        )
                    } else {
                        collectionRepository.updateWasteWaterWeight(initWasteWaterFlowInfo, wasteWaterFlowInfo)
                    }

                    // 更新水地油管流量计计数
                    if (wasteWaterFlowInfo.positiveAccumulationVal > 0.0) {
                        iFlowVolumeErrorParser.updateWasteWaterVolume(wasteWaterFlowInfo.positiveAccumulationVal.toString())
                    }

                    withContext(Dispatchers.Main) {
                        wasteWaterFlowInfoLiveData.value = wasteWaterFlowInfo
                    }

                    MLog.e(wasteWaterFlowInfo.toString())
                } catch (e: ModbusError) {
                    MLog.e("water modBus error: %s", e.message)
                }
            }
        }
        workStateLiveData.value = WorkStatus.WORKING
    }

    fun stopWatchWasteWaterPipeInfo(isOutput: Boolean) {
        wasteWaterJob?.cancel()
        wasteWaterJob = null

        checkWorkState(isOutput, WATER_VOLUME_NAME2)
//        workStateLiveData.value = if (oilJob == null) WorkStatus.IDLE else WorkStatus.WORKING
        insertWasteWaterRecord()
    }
    //新增-含油污水-end


    fun stopWatchOilPipeInfo(isOutput: Boolean) {
        oilJob?.cancel()
        oilJob = null
        checkWorkState(isOutput, OIL_VOLUME_NAME)
//        workStateLiveData.value = if (waterJob == null) WorkStatus.IDLE else WorkStatus.WORKING
        insertOilRecord()
    }

    fun stopWatchWaterPipeInfo(isOutput: Boolean) {
        waterJob?.cancel()
        waterJob = null
        checkWorkState(isOutput, WATER_VOLUME_NAME)

//        workStateLiveData.value = if (oilJob == null) WorkStatus.IDLE else WorkStatus.WORKING
        insertWaterRecord()
    }

    fun startWatchUltraSonicInfo(
        measureMenuItem: MeasureMenuItem,
        isOutput: Boolean?,
        wasteTypeEnum: WasteTypeEnum
    ) {
        sonicJob?.cancel()
        createLocalWaterRecord(measureMenuItem, wasteTypeEnum)
        val iFlowVolumeErrorParser =
//            FakeInVolumeErrorParserImpl()
            if (isOutput == false) InFlowVolumeErrorParserImpl(flowVolumeRepository) else OutFlowVolumeErrorParserImpl(
                flowVolumeRepository
            )

        sonicJob = viewModelScope.launch(Dispatchers.IO) {
            tickerFlow(1000).collect {
                try {
                    val ultraSonicFlowInfo = coroutineScope {
                        getSonicFlowInfo(isOutput)
                    }

                    if (initSonicFlowInfo == null) {
                        initSonicFlowInfo = ultraSonicFlowInfo
                        checkUltraSonicPipeError(
                            ultraSonicFlowInfo.positiveAccumulationVal,
                            iFlowVolumeErrorParser
                        )
                    } else {
                        collectionRepository.updateSonicWeight(
                            initSonicFlowInfo,
                            ultraSonicFlowInfo
                        )
                    }

                    // 更新水地油管流量计计数
                    if (ultraSonicFlowInfo.positiveAccumulationVal > 0.0) {
                        iFlowVolumeErrorParser.updateSonicVolume(ultraSonicFlowInfo.positiveAccumulationVal.toString())
                    }

                    withContext(Dispatchers.Main) {
                        sonicInfoLiveData.value = ultraSonicFlowInfo
                    }

                    MLog.e(ultraSonicFlowInfo.toString())
                } catch (e: ModbusError) {
                    MLog.e("water modBus error: %s", e.message)
                }
            }
        }
        workStateLiveData.value = WorkStatus.WORKING
    }

    fun stopWatchUltraSonicInfo(isOutput: Boolean) {
        viewModelScope.launch {
            sonicJob?.cancelAndJoin()
            sonicJob = null
            checkWorkState(isOutput, ULTRASONIC_NAME)
//        workStateLiveData.value = if (oilJob == null) WorkStatus.IDLE else WorkStatus.WORKING
            insertSonicRecord()
        }

    }

    private fun checkWorkState(isOutput: Boolean, pipeName: String) {
        viewModelScope.launch {
            val otherMenuItems =
                menuConfigRepository.getMenuItemsByOutput(isOutput)
                    .filter { it.isFlow() && it.name != pipeName }

            // 其他都处于空闲状态
            if (otherMenuItems.none { getRelativeFlowJob(it) != null }) {
                workStateLiveData.value = WorkStatus.IDLE
            } else {
                workStateLiveData.value = WorkStatus.WORKING
            }
        }
    }

    private fun getRelativeFlowJob(measureMenuItem: MeasureMenuItem): Job? {
        return when {
            measureMenuItem.isOil() -> oilJob
            measureMenuItem.isWasteWater()->wasteWaterJob
            measureMenuItem.isWater() -> waterJob
            measureMenuItem.isUltraSonic() -> sonicJob
            else -> null
        }
    }

    /**
     *
     */
    private suspend fun checkOilPipeError(
        positiveAccumulationVal: Double,
        iFlowVolumeErrorParser: IFlowVolumeErrorParser
    ) {
        val measureMenuItemByName = menuConfigRepository.getMeasureMenuItemByName(OIL_VOLUME_NAME)
        iFlowVolumeErrorParser.checkOil(positiveAccumulationVal, measureMenuItemByName.alias)
            ?.let { volumeErrorInfo ->
                val set = (volumeErrorsLiveData.value?.toMutableSet() ?: mutableSetOf()).apply {
                    add(volumeErrorInfo)
                }
                volumeErrorsLiveData.postValue(set)
            }

    }

    private suspend fun checkWaterPipeError(
        positiveAccumulationVal: Double,
        iFlowVolumeErrorParser: IFlowVolumeErrorParser
    ) {
        val measureMenuItemByName = menuConfigRepository.getMeasureMenuItemByName(WATER_VOLUME_NAME)
        iFlowVolumeErrorParser.checkWater(positiveAccumulationVal, measureMenuItemByName.alias)
            ?.let { volumeErrorInfo ->
                val set = (volumeErrorsLiveData.value?.toMutableSet() ?: mutableSetOf()).apply {
                    add(volumeErrorInfo)
                }
                volumeErrorsLiveData.postValue(set)
            }
    }

    //新增废水
    private suspend fun checkWasteWaterPipeError(
        positiveAccumulationVal: Double,
        iFlowVolumeErrorParser: IFlowVolumeErrorParser
    ) {
        val measureMenuItemByName2 =
            menuConfigRepository.getMeasureMenuItemByName(WATER_VOLUME_NAME2)
        iFlowVolumeErrorParser.checkWasteWater(positiveAccumulationVal, measureMenuItemByName2.alias)
            ?.let { volumeErrorInfo ->
                val set = (volumeErrorsLiveData.value?.toMutableSet() ?: mutableSetOf()).apply {
                    add(volumeErrorInfo)
                }
                volumeErrorsLiveData.postValue(set)
            }
    }


    private suspend fun checkUltraSonicPipeError(
        positiveAccumulationVal: Double,
        iFlowVolumeErrorParser: IFlowVolumeErrorParser
    ) {
        val measureMenuItemByName = menuConfigRepository.getMeasureMenuItemByName(ULTRASONIC_NAME)
        iFlowVolumeErrorParser.checkSonic(positiveAccumulationVal, measureMenuItemByName.alias)
            ?.let { volumeErrorInfo ->
                val set = (volumeErrorsLiveData.value?.toMutableSet() ?: mutableSetOf()).apply {
                    add(volumeErrorInfo)
                }
                volumeErrorsLiveData.postValue(set)
            }
    }
//    fun <T> checkCurrWorkStatus(
//        currWorkStatus: WorkStatus? = currWorkStatusLiveData.value,
//        beforeWork: T,
//        working: T
////        finished: T
//    ): T? {
//        return when (currWorkStatus) {
//            WorkStatus.BEFORE_WORK -> beforeWork
//            WorkStatus.WORKING -> working
////            WorkStatus.FINISHED -> finished
//            else -> null
//        }
//    }

//    fun <T> checkCurrWorkType(
//        currWorkType: WorkType? = currWorkTypeLiveData.value,
//        flow: T,
//        weight: T
//    ): T? {
//        return when (currWorkType) {
//            WorkType.FLOW -> flow
//            WorkType.WEIGHT -> weight
//            else -> null
//        }
//    }

//    fun <T> checkFlowType(currFlowType: FlowType? = flowType.value, oil: T, water: T): T? {
//        return when (currFlowType) {
//            FlowType.OIL -> oil
//            FlowType.WATER -> water
//            else -> null
//        }
//    }

    fun deleteRecord(record: CollectionRecord) {
        viewModelScope.launch {
            collectionRepository.deleteRecord(record)
        }
    }

    private fun createLocalOilRecord(
        wasteTypeEnum: WasteTypeEnum,
        measureMenuItem: MeasureMenuItem
    ) {
        viewModelScope.launch {
//            val menuItems = menuConfigRepository.getMenuItemsByOutput(output == true)
            collectionRepository.createLocalRecordInMemory(
                wasteTypeEnum,
                System.currentTimeMillis(),
                measureMenuItem
            )
        }
//        updateCachedOrder()

    }

    private fun createLocalWaterRecord(
        measureMenuItem: MeasureMenuItem,
        wasteTypeEnum: WasteTypeEnum
    ) {
//        updateCachedOrder()
        viewModelScope.launch {
//            val menuItems = menuConfigRepository.getMenuItemsByOutput(output == true)
            collectionRepository.createLocalRecordInMemory(
                wasteTypeEnum,
                System.currentTimeMillis(),
                measureMenuItem
            )
        }

    }

    private fun createLocalWasteWaterRecord(
        measureMenuItem: MeasureMenuItem,
        wasteTypeEnum: WasteTypeEnum
    ) {
//        updateCachedOrder()
        viewModelScope.launch {
//            val menuItems = menuConfigRepository.getMenuItemsByOutput(output == true)
            collectionRepository.createLocalRecordInMemory(
                wasteTypeEnum,
                System.currentTimeMillis(),
                measureMenuItem
            )
        }

    }

    fun getRecordsLiveData() = collectionRepository.recordsLiveData

    private fun insertWaterRecord() {
        viewModelScope.launch {
            initWaterFlowInfo = null
            updateCachedOrder().join()
            collectionRepository.insertWaterRecord(cachedOrder)
        }
    }

    private fun insertWasteWaterRecord() {
        viewModelScope.launch {
            initWasteWaterFlowInfo = null
            updateCachedOrder().join()
            collectionRepository.insertWasteWaterRecord(cachedOrder)
        }
    }

    private fun insertSonicRecord() {
        viewModelScope.launch {
            initSonicFlowInfo = null
            updateCachedOrder().join()
            collectionRepository.insertSonicRecord(cachedOrder)
        }
    }

    private fun insertOilRecord() {
        viewModelScope.launch {
            initOilFlowInfo = null
            updateCachedOrder().join()
            collectionRepository.insertOilRecord(cachedOrder)
        }
    }


    fun loadLocalRecords() {
        viewModelScope.launch(Dispatchers.IO) {
            collectionRepository.loadCollectionRecords(cachedOrder)
        }
    }

//    fun submitTest() {
//        viewModelScope.launch {
//            checkState(submitEvent, Results.Loading)
//        }
//    }

    fun submit(
        detail: ApplicationDetail?,
        collectionRecords: List<CollectionRecord>,
        print: Boolean
    ) {
        val id = detail?.id
        if (id == null) {
            toast { "请选择接收对象" }
            return
        }

        viewModelScope.launch {
            val endTime =
                if (cachedOrder.endTime != null) cachedOrder.endTime else System.currentTimeMillis()
            val groupBy = collectionRecords.groupBy { it.wasteType }
            val wasteMap = mutableMapOf<String, List<String>>()
            groupBy.forEach {
                val originWeight =
                    FormatUtils.format3Decimal(it.value.sumByDouble { record -> record.originWeight.toDouble() })
                val finalWeight =
                    FormatUtils.format3Decimal(it.value.sumByDouble { record -> (if (record.finalWeight == null) record.originWeight else record.finalWeight)!!.toDouble() })

/*                if (WasteTypeEnum.getWasteType(it.key)?.isSolid() == true) {
                    val oriWeightInTon = BigDecimal(originWeight).divide(BigDecimal(1000))
                        .setScale(3, RoundingMode.DOWN).toPlainString()
                    val finalWeightInTon = BigDecimal(finalWeight).divide(BigDecimal(1000))
                        .setScale(3, RoundingMode.DOWN).toPlainString()
                    wasteMap[it.key] = listOf(oriWeightInTon, finalWeightInTon)
                }*/
//                else if (WasteTypeEnum.getWasteType(it.key) == WasteTypeEnum.RESIDUAL_OIL) {
//                    // 残油 需要乘上密度0.9
//                    val oilOriginWeight = BigDecimal(originWeight).multiply(BigDecimal(OIL_DENSITY))
//                        .setScale(2, RoundingMode.HALF_DOWN).toPlainString()
//                    val oilFinalWeight = BigDecimal(finalWeight).multiply(BigDecimal(OIL_DENSITY))
//                        .setScale(2, RoundingMode.HALF_DOWN).toPlainString()
//                    wasteMap[it.key] = listOf(oilOriginWeight, oilFinalWeight)
//                }
/*                else {
                    wasteMap[it.key] = listOf(originWeight, finalWeight)
                }*/
                wasteMap[it.key] = listOf(originWeight, finalWeight)
            }
//            val wasteInfoMap = collectionRecords.associateBy({ it.wasteType },
//                {
//                    listOf(
//                        it.originWeight.toString(),
//                        (if (it.finalWeight == null) it.originWeight else it.finalWeight).toString()
//                    )
//                })

            //对提交污染物做判断
       /*       var myDetail = detail.applicationItems
                 var chooseType = wasteMap.keys
                 Log.e("------->1",myDetail.toString())
                 Log.e("------->2",wasteMap.keys.toString())
                 val heList =  ArrayList<String>()
                 for(choose in chooseType){
                     for(details in myDetail){
                         if (details.wasteType == null) {
                             toast { "wasteType为null,非三中污染物之中" }
                             return@launch
                         }
                         if (details.wasteType.contains(choose)) {
                             heList.add(choose)
                         }
                }
            }

            if(chooseType.size!=0){
                if(heList.size!= chooseType.size) {
                    toast { "提交污染物未在申报单内" }
                    Log.e("------->3", heList.toString())
                    Log.e("------->4", chooseType.toString())
                    var strs1: StringBuilder? = StringBuilder()
                    //选中的
                    for (s in chooseType) {
                        if (s.toString().equals("C110011")) {
                            strs1?.append("含油污水 ")
                        }
                        if (s.toString().equals("C110012")) {
                            strs1?.append("生活污水 ")
                        }
                        if (s.toString().equals("C110013")) {
                            strs1?.append("废机油 ")
                        }
                    }
                    var dets: StringBuilder? = StringBuilder()
                    //申报的
                    for(det in myDetail){
                        if (det.wasteType.equals("C110011")) {
                            dets?.append("含油污水 ")
                        }
                        if (det.wasteType.equals("C110012")) {
                            dets?.append("生活污水 ")
                        }
                        if (det.wasteType.equals("C110013")) {
                            dets?.append("废机油 ")
                        }
                    }

                    for (s in chooseType) {
                        for(det in myDetail){
                            if(!s.contains(det.wasteType)){
                                Log.e("------->7", "您选择的"+s.toString()+"不在申报单内")
                            }
                        }
                    }

                    Log.e("------->5", "您选择了"+strs1.toString())
                    Log.e("------->6","您申报了"+ dets.toString())
                    return@launch
                }else{
                    toast{"yes"}
                }
            }*/


           val request = PostApplicationRequest(cachedOrder.startTime, endTime!!, wasteMap)
//            val url = "http://www.baidu.com"
//            submitEvent.value =
//                ViewState(
//                    data = if (print) getPrintInfo(
//                        url,
//                        detail,
//                        wasteMap
//                    ) else EmptyPrintInfo,
//                    isSuccess = true,
//                    isLoadMore = false
//                )
               checkState(submitEvent, Results.Loading)
               checkState2(
                   submitEvent,
                   collectionRepository.submit(id, request),
                   successAction = { url, isLoadMore ->
                       collectionRepository.deleteCachedOrderById(cachedOrder.id)
                       submitEvent.value =
                           ViewState(
                               //原打印信息
                               data = if (print) getPrintInfo(
                                   url,
                                   detail,
                                   wasteMap
                               ) else EmptyPrintInfo,
                               isSuccess = true,
                               isLoadMore = isLoadMore
                           )
                   })
        }
    }


    fun updateCachedOrder(
        applicationId: String? = null,
        companyName: String? = null
    ): Job {
        return viewModelScope.launch {
            if (applicationId != null) {
                val queryResult = collectionRepository.findCachedOrderByApplicationId(applicationId)

                // 该接收单没有产生暂存单
                if (queryResult?.id == null) {
                    checkWhetherInsert(companyName, applicationId)
                } else {
                    // 已经生成了对应的暂存单
                    copyCachedOrder(queryResult)
                    loadLocalRecords()
                }
            } else {
                checkWhetherInsert(companyName, applicationId)
            }
        }
    }

    private suspend fun checkWhetherInsert(companyName: String?, applicationId: String?) {
        val currentTime = System.currentTimeMillis()
        if (!cachedOrder.hasSetStartTime()) {
            cachedOrder.startTime = currentTime
            cachedOrder.sn = deviceInfoRepository.sn
            collectionRepository.insertCachedOrder(cachedOrder)
        }
        collectionRepository.updateCachedOrder(
            cachedOrder,
            companyName = companyName,
            applicationId = applicationId
        )
    }

    fun updateCachedOrderByEndTime(endTime: Long): Job {
        return viewModelScope.launch {
            if (BuildConfig.FLAVOR == "flavor_beta") {
                val records =
                    collectionRepository.getCollectionRecordsFromDB(cachedOrder)
                val uselessRecords = records?.filter { it.originWeight == 0f }
                //  如果全是无意义数据 则cacheOrder本身也需要剔除掉
                if (uselessRecords != null && uselessRecords.size == records.size) {
                    collectionRepository.deleteCachedOrderById(cachedOrder.id)
                }
            }

            collectionRepository.updateCachedOrder(cachedOrder, endTime = endTime)
        }
    }

    //-----------cached order has existed when enters CollectionActivity
    fun queryCachedOrderById(cachedOrderId: Long): Job {
        return viewModelScope.launch {
            val queryResult = collectionRepository.queryCachedOrderById(cachedOrderId)
            copyCachedOrder(queryResult)
            withContext(Dispatchers.IO) {
                cachedOrder.applicationDetail =
                    collectionRepository.getCachedApplicationDetail(queryResult.id)
            }
            MLog.e("queryCachedOrderById = $queryResult")
            loadLocalRecords()
        }
    }

    private fun copyCachedOrder(queryResult: CachedOrder) {
        cachedOrder.applicationId = queryResult.applicationId
        cachedOrder.companyName = queryResult.companyName
        cachedOrder.endTime = queryResult.endTime
        cachedOrder.id = queryResult.id
        cachedOrder.startTime = queryResult.startTime
        cachedOrder.sn = queryResult.sn
    }

    fun getApplicationDetail(): ApplicationDetail? {
        return cachedOrder.applicationDetail
    }

    fun cacheApplicationDetail(detail: ApplicationDetail) {
        val cachedOrderId = cachedOrder.id ?: return
        viewModelScope.launch(Dispatchers.IO) {
            collectionRepository.cacheApplicationDetail(cachedOrderId, detail)
        }
    }

    fun startWatchWeightInfo() {
        weightJob?.cancel()
        weightJob = viewModelScope.launch(Dispatchers.IO) {
            tickerFlow(1000).collect {
                try {
                    val weightInfo = coroutineScope {
                        DeviceControllerManager.readWeightInfo()
                    }
                    this@CollectionViewModel.weightInfo = weightInfo
                    withContext(Dispatchers.Main) {
                        weightLiveData.value = weightInfo.weight
                    }
                } catch (e: ModbusError) {
                    MLog.e(e.message.toString())
                }
            }
        }
    }

    fun stopWatchWeightInfo() {
        weightJob?.cancel()
        weightJob = null
    }

    fun recordWeight(code: String) {
        if (System.currentTimeMillis() - lastWeightClickTime > 5000) {
            viewModelScope.launch {
                val weightInfo = this@CollectionViewModel.weightInfo

                if (weightInfo == null || weightInfo.weight == 0) {
                    toast { "当前重量为0，请确认是否有将污染物放置在称重计上" }
                    return@launch
                }

                updateCachedOrder().join()
                collectionRepository.insertWeightRecord(weightInfo.weight, cachedOrder, code)
            }
            lastWeightClickTime = System.currentTimeMillis()
        } else {
            toast { "点击频率过快，请稍后" }
        }

    }

    fun updateAfterChecked(infos: MutableList<CollectionRecord>): Job {
        return viewModelScope.launch {
            infos.forEach {
                collectionRepository.updateCollectionRecord(it)
            }
        }
    }

    // 是否处于空闲状态  三条管道都是处于空闲状态
    fun isIdle() = waterJob == null && oilJob == null && wasteWaterJob == null

//    fun checkShowWeightGuide() {
//        viewModelScope.launch {
//            isShowProgressWeightGuide.value =
//                collectionRepository.getWeightRecordByCachedOrderId(
//                    cachedOrder.id
//                ) == null
//        }
//    }

    private fun getWaterFlowInfo(isOutput: Boolean?): WaterFlowInfo {
        return if (isOutput == true) DeviceControllerManager.readOutputWaterFlowInfo() else DeviceControllerManager.readInputWaterFlowInfo()
    }

    //新增-含油污水-start
    private fun getWasteWaterFlowInfo(isOutput: Boolean?): WaterFlowInfo {
        return if (isOutput == true) DeviceControllerManager.readOutputWasteWaterFlowInfo() else DeviceControllerManager.readInputWasteWaterFlowInfo()
    }
    //新增-含油污水-end

    private fun getOilFlowInfo(isOutput: Boolean?) =
        if (isOutput == true) DeviceControllerManager.readOutOilFlowInfo() else DeviceControllerManager.readInputOilFlowInfo()

    private fun getSonicFlowInfo(isOutput: Boolean?): UltraSonicFlowInfo {
        return if (isOutput == true) DeviceControllerManager.readOutputSonicFlowInfo() else DeviceControllerManager.readInputSonicFlowInfo()
    }

    private suspend fun getPrintInfo(
        url: String?,
        detail: ApplicationDetail,
        wasteMap: MutableMap<String, List<String>>
    ): PrintInfo {
        //todo: 下面的fromShip以及toShip的赋值可以优化
        val fromShip: String?
        val toShip: String?
        if (ApplicationTypeEnum.getApplicationType(detail.recordType) == ApplicationTypeEnum.TRANSPORT) {
            // 转出任务单
            // fromShip = detail.shipInfo?.shipName
            fromShip = detail.receiveShipName
            toShip = detail.shipName
        } else {
            // 接收任务单
            fromShip = detail.producerName
            toShip = if (deviceInfoRepository.shipName.isNotEmpty()) {
                deviceInfoRepository.shipName
            } else {
                val results = mainRepository.getHostShipInfo()
                if (results is Results.Success<ShipInfo>) {
                    deviceInfoRepository.shipName = results.data.shipName ?: ""
                    results.data.shipName
                } else {
                    ""
                }
            }
        }
        val wasteInfoMap = wasteMap.map {
            val wasteTypeEnum = WasteTypeEnum.getWasteType(it.key)
            /*        val unit = when {
                        wasteTypeEnum?.isSolid() == true -> "T"
                        else -> "m^3"
                    }*/
            val unit = "m^3"
//                wasteTypeEnum?.getUnitText(it.value[1])
//                when {
//                wasteTypeEnum?.isSolid() == true -> {
//                    "T"
//                }
//                wasteTypeEnum == WasteTypeEnum.RESIDUAL_OIL -> {
//                    // 密度 0.9
//                    val weight =
//                        BigDecimal(it.value[1])
//                            .multiply(BigDecimal(0.9))
//                            .setScale(3, RoundingMode.HALF_DOWN)
//                            .toPlainString()
//                    "立方米(约$weight T)"
//                }
//                else -> {
//                    "立方米(约${it.value[1]} T)"
//                }
//            }
            val s =
                "${wasteTypeEnum?.desc}：${FormatUtils.format3Decimal(it.value[1].toDoubleOrNull())}$unit"
            MLog.e("s = $s")
            s
        }
        return PrintInfo(
            fromShip,
            toShip,
            FormatUtils.formatTimeYMD(System.currentTimeMillis()), wasteInfoMap,
            url
        )
    }

    fun updateCollectionRecord(record: CollectionRecord) {
        viewModelScope.launch {
            collectionRepository.updateCollectionRecord(record)
        }
    }

    fun isAllWasteTypeSelected(collectionRecords: MutableList<CollectionRecord>): Boolean {
        // 危废种类为选择
        for (record in collectionRecords) {
            if (record.wasteType.isEmpty() || record.wasteType == WasteTypeEnum.OIL_UNDEFINE.code ||
                record.wasteType == WasteTypeEnum.WATER_UNDEFINE.code || record.wasteType == WasteTypeEnum.ULTRA_UNDEFINE.code||record.wasteType == WasteTypeEnum.WASTE_WATER_UNDEFINE.code
            ) {
                return false
            }
        }
        return true
    }

    fun addNotRecordToCurrent(type: Int, isOutput: Boolean?) {
        viewModelScope.launch {
            when (type) {
                VolumeErrorInfo.WATER -> {
                    updateCachedOrder().join()
                    collectionRepository.addNotRecordToFlow(
                        if (isOutput == true) flowVolumeRepository.totalOutWaterErrorVolume else flowVolumeRepository.totalInWaterErrorVolume,
                        WasteTypeEnum.WATER_UNDEFINE,
                        cachedOrder
                    )
                }
                VolumeErrorInfo.WASTE_WATER -> {
                    updateCachedOrder().join()
                    collectionRepository.addNotRecordToFlow(
                        if (isOutput == true) flowVolumeRepository.totalOutWasteWaterErrorVolume else flowVolumeRepository.totalInWasteWaterErrorVolume,
                        WasteTypeEnum.WASTE_WATER_UNDEFINE,
                        cachedOrder
                    )
                }
                VolumeErrorInfo.OIL -> {
                    updateCachedOrder().join()
                    collectionRepository.addNotRecordToFlow(
                        if (isOutput == true) flowVolumeRepository.totalOutOilErrorVolume else flowVolumeRepository.totalInOilErrorVolume,
                        WasteTypeEnum.OIL_UNDEFINE,
                        cachedOrder
                    )
                }
                VolumeErrorInfo.SONIC -> {
                    updateCachedOrder().join()
                    collectionRepository.addNotRecordToFlow(
                        if (isOutput == true) flowVolumeRepository.totalOutSonicErrorVolume else flowVolumeRepository.totalInSonicErrorVolume,
                        WasteTypeEnum.ULTRA_UNDEFINE,
                        cachedOrder
                    )
                }
            }

            ignoreNotRecord(type, isOutput)
        }

    }

    fun ignoreNotRecord(type: Int, isOutput: Boolean?) {
        if (type == VolumeErrorInfo.WATER) {
            if (isOutput == true) {
                flowVolumeRepository.totalOutWaterErrorVolume = 0f
            } else {
                flowVolumeRepository.totalInWaterErrorVolume = 0f
            }
        } else if (type == VolumeErrorInfo.WASTE_WATER) {
            if (isOutput == true) {
                flowVolumeRepository.totalOutWasteWaterErrorVolume = 0f
            } else {
                flowVolumeRepository.totalInWasteWaterErrorVolume = 0f
            }
        } else if (type == VolumeErrorInfo.OIL) {
            if (isOutput == true) {
                flowVolumeRepository.totalOutOilErrorVolume = 0f
            } else {
                flowVolumeRepository.totalInOilErrorVolume = 0f
            }
        } else if (type == VolumeErrorInfo.SONIC) {
            if (isOutput == true) {
                flowVolumeRepository.totalOutSonicErrorVolume = 0f
            } else {
                flowVolumeRepository.totalInSonicErrorVolume = 0f
            }
        }

        val errors = volumeErrorsLiveData.value?.toMutableSet()
        errors?.removeAll { it.type == type }
        volumeErrorsLiveData.value = errors
    }

    companion object {
        val EmptyPrintInfo = PrintInfo("", "", "", emptyList(), "")

        //        private const val PIPE_COUNT = 2
//        private const val ERROR_DELTA = 0.01
    }
}

/**
 * 当前的工作状态: 开始工作前、工作中
 */
enum class WorkStatus {
    IDLE,
    WORKING,
//    FINISHED,
    ;
}

/**
 * 未选择、输油管、输水管以及称重
 */
//enum class WorkType {
//    FLOW,
//    WEIGHT,
//    ;
//}
//
//enum class FlowType {
//    OIL,
//    WATER,
//    ;
//}